#include "HFFDecodeThread.h"
#include "HFFDecode.h"
#include <thread>
#include <iostream>
#include <opencv2/opencv.hpp>
#include "hscope.h"

extern "C" {
#include "libavutil/avutil.h"
#include "libavformat/avformat.h"
}


HFFDecodeThread::HFFDecodeThread()
{
  decode_mode = DEFAULT_DECODE_MODE;
  HThread::setSleepPolicy(HThread::NO_SLEEP, 1); 
}


HFFDecodeThread::~HFFDecodeThread()
{	
	isExit = true;
}


void HFFDecodeThread::Close()
{
	Clear();
	HFFDecode::Close();
  hframe.buf.cleanup();
	//等待线程退出
	isExit = true;
}

bool HFFDecodeThread::doPrepare()
{
    bool ret = true;
    //ret = Open();
    return ret;
}

bool HFFDecodeThread::doFinish()
{
    Close();
    return true; 
}

int HFFDecodeThread::stop()
{
	isExit = true;
	return HThread::stop();
}

void HFFDecodeThread::Clear()
{
	m_mux.lock();
	while (!packs.empty())
	{
		AVPacket *pkt = packs.front();
		XFreePacket(&pkt);
		packs.pop_front();
	}

	m_mux.unlock();
}


//取出一帧数据，并出栈，如果没有返回NULL
AVPacket *HFFDecodeThread::Pop()
{
	m_mux.lock();
	if (packs.empty())
	{
		m_mux.unlock();
		return NULL;
	}
	AVPacket *pkt = packs.front();
	packs.pop_front();
	m_mux.unlock();
	return pkt;
}


void HFFDecodeThread::Push(AVPacket *pkt, UserData* user_data)
{
	if (!pkt)return;
	//阻塞
	while (!isExit)
	{
		m_mux.lock();
		if (packs.size() < maxList)
		{
			packs.push_back(pkt);

      if (user_data != NULL) {
        _userDatas.insert({user_data->id, user_data});
      }

			m_mux.unlock();
			break;
		}

		m_mux.unlock();
		std::this_thread::sleep_for(std::chrono::milliseconds(1));
	}
}


void saveYUV420PToJPG(AVFrame * frame, const std::string& outputFilePath) {
  // 计算 YUV 数据大小
  int width = frame->width;
  int height = frame->height;
  size_t frameSize = width * height * 3 / 2;
  int y_size = frame->width * frame->height;
  uint8_t buf[frameSize] = {0};

  memcpy(buf, frame->data[0],  y_size);
  memcpy(buf + y_size, frame->data[1],  y_size / 4);
  memcpy(buf + y_size + y_size / 4, frame->data[2], y_size / 4);

  // 将 YUV420P 数据转换为 BGR
  cv::Mat yuvImage(height + height / 2, width, CV_8UC1, buf);
  cv::Mat bgrImage;
  cv::cvtColor(yuvImage, bgrImage, cv::COLOR_YUV2BGR_I420);

  // 保存 BGR 图像为 JPG 文件
  if (!cv::imwrite(outputFilePath, bgrImage)) {
      std::cerr << "无法保存 JPG 文件: " << outputFilePath << std::endl;
  }
}

void saveNV12ToJPG(AVFrame * frame, const std::string& outputFilePath) {
  // 获取帧的宽度和高度
  int width = frame->width;
  int height = frame->height;

  // 计算 YUV 数据大小
  size_t y_size = width * height;
  size_t uv_size = y_size / 2; // NV12 的 UV 分量大小

  // 创建缓冲区并复制 YUV 数据
  uint8_t buf[y_size + uv_size];
  memcpy(buf, frame->data[0], y_size);                // Y 分量
  memcpy(buf + y_size, frame->data[1], uv_size);     // UV 分量

  // 创建 NV12 图像的 cv::Mat 对象
  cv::Mat nv12Image(height + height / 2, width, CV_8UC1, buf);
  cv::Mat bgrImage;

  // 将 NV12 数据转换为 BGR
  cv::cvtColor(nv12Image, bgrImage, cv::COLOR_YUV2BGR_NV12);

  // 保存 BGR 图像为 JPG 文件
  if (!cv::imwrite(outputFilePath, bgrImage)) {
      std::cerr << "无法保存 JPG 文件: " << outputFilePath << std::endl;
  }
}


static std::string timestampToDateTimeString(long long timestamp) {
    // 将时间戳转换为 tm 结构体
    int ms = timestamp % 1000;
    std::time_t timestamp_t = (std::time_t)timestamp/1000;
    std::tm* tmPtr = std::localtime(&timestamp_t);
    if (!tmPtr) {
        return "Invalid timestamp";
    }

    // 使用 stringstream 格式化日期和时间
    std::stringstream ss;
    ss << std::put_time(tmPtr, "%Y-%m-%d_%H:%M:%S");
    ss << "_" << std::to_string(ms);

    return ss.str();
}

void HFFDecodeThread::doTask()
{
	AVPacket *pkt = Pop();
  if(pkt == NULL){
    std::this_thread::sleep_for(std::chrono::milliseconds(1));
    return ;
  }

  //printf("file:%s function:%s line:%d time3 = %lld\n", __FILE__, __FUNCTION__, __LINE__, gethrtime_us() / 1000);
  int pkt_pts = pkt->pts;
  if (_userDatas.size() > 0) {
    auto it = _userDatas.find(pkt_pts);
    if (it != _userDatas.end()) {
      it->second->send_decoder_time = gethrtime_us() / 1000;
    } 
  }
  //printf("file:%s function:%s line:%d time4 = %lld\n", __FILE__, __FUNCTION__, __LINE__, gethrtime_us() / 1000);
	bool re = Send(pkt);
  //printf("file:%s function:%s line:%d time7 = %lld\n", __FILE__, __FUNCTION__, __LINE__, gethrtime_us() / 1000);
	if (!re){
		std::this_thread::sleep_for(std::chrono::milliseconds(1));
		return ;
	}

	//一次send 多次recv
	while (!isExit){
		AVFrame * frame = Recv();
		if (!frame) break;
    long long finish_decode_time = gethrtime_us() / 1000;

    //printf("file:%s function:%s line:%d _userDatas.size():%d\n", __FILE__, __FUNCTION__, __LINE__, _userDatas.size());
    
    if (_userDatas.size() > 0) {
      std::unique_lock<std::mutex> locker_(m_mux);
      printf("file:%s function:%s line:%d _userDatas.size():%ld\n", __FILE__, __FUNCTION__, __LINE__, _userDatas.size());
      int user_data_id = frame->pts;
      auto it = _userDatas.find(user_data_id);
      if (it == _userDatas.end()) {
        printf("Error: not find user data*************************************\n");
      } else {
        printf("**sei time =            %lld %s\n", it->second->sei_time, timestampToDateTimeString(it->second->sei_time).c_str());
        printf("**recv frame time =     %lld %s\n", it->second->recv_frame_time, timestampToDateTimeString(it->second->recv_frame_time).c_str());
        printf("**send decoder time =   %lld %s\n", it->second->send_decoder_time, timestampToDateTimeString(it->second->send_decoder_time).c_str());
        printf("**finish decode time =  %lld %s\n", finish_decode_time, timestampToDateTimeString(finish_decode_time).c_str());

        char file_name[1024] = {0};
        // sprintf(file_name, "%s-%s-%s.jpg", std::to_string(it->second->sei_time).c_str(), 
        //                                    std::to_string(it->second->recv_frame_time).c_str(), 
        //                                    std::to_string(finish_decode_time).c_str());
        sprintf(file_name, "%s-%s-%s.jpg", timestampToDateTimeString(it->second->sei_time).substr(11).c_str(), 
                                           timestampToDateTimeString(it->second->recv_frame_time).substr(11).c_str(), 
                                           timestampToDateTimeString(finish_decode_time).substr(11).c_str());
        
        printf("file_name = %s  frame->format=%d\n", file_name, frame->format);
        std::thread([=] {
          if (AV_PIX_FMT_YUV420P == frame->format || AV_PIX_FMT_YUVJ420P == frame->format) {
            printf("***format :%d\n", frame->format);
            saveYUV420PToJPG(frame, file_name);
          } else if (AV_PIX_FMT_NV12 == frame->format) {
            //printf("format :%d\n", frame->format);
            //saveNV12ToJPG(frame, file_name);
          }
          defer(XFreeFrame((AVFrame**)&frame);)
        }).detach();

        free(it->second);
        _userDatas.erase(it);
      }
      printf("file:%s function:%s line:%d _userDatas.size():%ld\n", __FILE__, __FUNCTION__, __LINE__, _userDatas.size());
    }

    //std::cout << "frm->pts2:" << frame->pts << std::endl;

    //YUV数据写入文件
    // static int i = 10000;
    // std::fstream outFile(std::to_string(i++) + ".yuv", std::ios::out | std::ios::binary);
    // int y_size = frame->width * frame->height;
    // outFile.write((const char*)frame->data[0], y_size);
    // outFile.write((const char*)frame->data[1], y_size/4);
    // outFile.write((const char*)frame->data[2], y_size/4);


    //defer(XFreeFrame(&frame);)
	}
  std::this_thread::sleep_for(std::chrono::milliseconds(1));
}